package com.liruo.treasureattic.common.util.tree;

import com.liruo.treasureattic.common.util.tree.ci.Container;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Author:liruo
 * @Date:2022-12-15-18:22:41
 * @Desc
 */
public class TreeUtils {
    /**
     * 使用这个方法build
     *      表示并不是有只有一个顶级，而是有n个，返回结果就是这个n个顶级
     *          并且给这些顶级填充子级，以及属于其的内容
     * 缺点：必须传入List<Item>  List<Container<FSA, Item>> 也就是使用前需要转换
     */
    public static <FSA, C extends Container<FSA>>
    List<C> build(List<?> items, List<C> containers) {
        HashSet<FSA> FSASet = new HashSet<>(containers.size());
        List<C> firstLayerContainers = new ArrayList<>(containers.size() / 2);
        List<C> noFirstLayerContainers = new ArrayList<>(containers.size() / 2);

        containers.stream()
                //收集Container的FSA
                .peek(container ->FSASet.add(container.obtainFFSA()))
                //对Containers根据FA分组
                .collect(Collectors.groupingBy(Container::obtainSFSA))
                .forEach((FA, subContainers)->{
                    if(!FSASet.contains(FA)){
                        //FSA不在这群Container里，就放在最外层
                        firstLayerContainers.addAll(subContainers);
                    }else{
                        noFirstLayerContainers.addAll(subContainers);
                    }
                });
        firstLayerContainers.forEach(firstLayerFolder->
                TreeUtils.build(firstLayerFolder, items, noFirstLayerContainers));
        return firstLayerContainers;
    }

    /**
     * @param rootContainer 为该Container以及其子Container 填充url或者子Container
     * @param subContainerCandidates 根据这里面的Container的FSA与当前rootContainer比较
     * 不用删除url或者Container，因为删除可能更费时间
     */

    @SuppressWarnings("unchecked")
    public static <FSA, C extends Container<FSA>>
    void build(C rootContainer, List<?> items, List<C> subContainerCandidates) {
        //填充Container的item
        items.forEach(item->{
            if(rootContainer.isSubItem(item)){
                rootContainer.addItem(item);
            }
        });

        //填充当前Container的子Container
        subContainerCandidates.forEach(maybeSub->{
            if(rootContainer.isSubContainer(maybeSub)){
                rootContainer.addSubFContainer(maybeSub);
            }
        });

        //子Container重复动作
        rootContainer.obtainSubContainers()
                .forEach(rootSubContainer->
                        //这里实则没辙，因为rootSubContainer是一个?，虽然也是继承Container<FSA>
                        //但是rootSubContainer可能是一个和rootContainer不一样的类，因此build方法里编译器不确定泛型参数C的类型
                        //因为方法的参数subContainerCandidates是List<C> ，rootContainer是C，必须类型一样
                        //但是因为我认定rootSubContainer和subContainerCandidates的元素是同一个类，因此强转rootSubContainer
                        TreeUtils.build((C) rootSubContainer, items, subContainerCandidates));
    }
}
